/**
 * 返回自适应悬浮按钮
 * by swl
 * create 2021-10-11
 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'dva';
import styles from './style.less';
import ReactDOM from 'react-dom';
import { PrimaryC } from '../../../comps';
import ResizeObserver from 'resize-observer-polyfill';
import uuid from 'es6-uuid';
let myObserver = null;
class FixedButtonC extends Component {
  // 默认值
  static defaultProps = {
    title: '返回', // 当调用方不提供bottomHtml时，系统自带按钮上的title
    topHtml: '', // 除悬浮区域外，上面的html内容，必传项
    bottomHeight: 50, // 底部自动悬浮部分的高度，默认50px
    bottomHtml: '', // 底部悬浮区域html，不是必填项，当不传参时，组件默认提供一个内置按钮
    onClick: () => {}, // 当调用方不提供bottomHtml时，系统自带按钮的点击事件
    style: {}, // 若是悬浮状态，底部元素最外层样式设置
  };
  constructor(props) {
    super(props);
    this.state = {
      fixed: false, //是否悬浮
      topHtmlId: 'topHtmlId' + uuid(4),
      contentId: 'contentId' + uuid(4),
      bottomId: 'bottomId' + uuid(4),
    };
  }

  componentDidMount() {
    // 监听窗口变化
    window.addEventListener('resize', this.windowChange);
    // 监听topHtml变化
    myObserver = new ResizeObserver((entries, observer) => {
      entries.forEach((entry, index) => {
        this.windowChange();
      });
    });
    myObserver.observe(document.getElementById(this.state.topHtmlId));
  }

  UNSAFE_componentWillReceiveProps() {
    this.windowChange();
  }

  componentWillUnmount() {
    // 删除窗口大小的监听
    window.removeEventListener('resize', this.windowChange);
    // 取消对所有节点的监听
    myObserver.disconnect();
  }

  // 窗口大小变更触发
  windowChange = () => {
    const { bottomId, contentId } = this.state;
    const { bottomHeight } = this.props;
    setTimeout(() => {
      let screenHeigh = document.body.clientHeight;
      try {
        //获取按钮当前位置，判断是否需要悬浮
        const bottomTop = ReactDOM.findDOMNode(document.getElementById(bottomId)).getBoundingClientRect();
        const contentTop = ReactDOM.findDOMNode(document.getElementById(contentId)).getBoundingClientRect();
        screenHeigh = screenHeigh - 65 - bottomHeight; //65：底部高度+底部padding
        if (screenHeigh < bottomTop.top) {
          this.setState({
            fixed: true,
            otherHeight: contentTop.top + 65 + bottomHeight,
          });
        } else {
          this.setState({
            fixed: false,
          });
        }
      } catch (err) {
        this.setState({
          fixed: false,
        });
      }
    }, 200);
  };

  render() {
    const { title, bottomHeight, onClick, topHtml, bottomHtml, style } = this.props;
    const { fixed, bottomId, contentId, otherHeight, topHtmlId } = this.state;
    //内容部分高度计算
    const topHeight = `calc(100vh - ${otherHeight}px)`;

    return (
      <div className={styles.fixedButton} style={{ overflow: 'hidden' }}>
        <div id={contentId} className={styles.top_box} ref={(ref) => (this.child = ref)} style={{ height: fixed ? topHeight : 'auto', marginBottom: fixed ? bottomHeight : 0 }}>
          <div id={topHtmlId}>{topHtml}</div>
          {/* 用于定位按钮位置，判断是否需要固定底部 */}
          <div id={bottomId} style={{ height: '12px' }}></div>
        </div>
        {fixed ? (
          <div className={styles.button_fixed} style={{ height: bottomHeight + 'px', ...style }}>
            {bottomHtml ? (
              bottomHtml
            ) : (
              <div className={styles.button}>
                <PrimaryC title={title} onClick={onClick} />
              </div>
            )}
          </div>
        ) : bottomHtml ? (
          bottomHtml
        ) : (
          <div className={styles.button}>
            <PrimaryC title={title} onClick={onClick} />
          </div>
        )}
      </div>
    );
  }
}
// props默认值
FixedButtonC.propsTypes = {
  title: PropTypes.string, // 当调用方不提供bottomHtml时，系统自带按钮上的title
  topHtml: PropTypes.node, // 除悬浮区域外，上面的html内容，必传项
  bottomHeight: PropTypes.number, // 底部自动悬浮部分的高度
  bottomHtml: PropTypes.node, // 底部悬浮区域html，不是必填项，当不传参时，组件默认提供一个内置按钮
  onClick: PropTypes.func, // 当调用方不提供bottomHtml时，系统自带按钮的点击事件
  style: PropTypes.object, // 若是悬浮状态，底部元素最外层样式设置
};

export default FixedButtonC;
